package io.polly.thread.monitor;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import io.polly.common.constant.NotifyTypeEnum;
import io.polly.common.constant.QueueTypeEnum;
import io.polly.common.constant.RejectedTypeEnum;
import io.polly.common.entity.NotifyItem;
import io.polly.thread.DynamicExecutor;
import io.polly.thread.DynamicExecutorBuilder;
import io.polly.thread.util.NotifyHelper;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;

/**
 * @author ldz
 * @version V1.0
 * @title: AlarmManager
 * @description: TODO(用一句话描述该文件做什么)
 * @date: 2022/3/22 15:15
 */
@Slf4j
public class AlarmManager {

    private static final ExecutorService ALARM_EXECUTOR = DynamicExecutorBuilder.newBuilder()
            .threadPoolName("DynamicExecutor-alarm")
            .threadFactory("DynamicExecutor-alarm")
            .corePoolSize(1)
            .maximumPoolSize(2)
            .workQueue(QueueTypeEnum.LINKED_BLOCKING_QUEUE.getName(), 2000, false)
            .rejectedExecutionHandler(RejectedTypeEnum.ABORT_POLICY.getName())
            .buildCommonExecutor();

    private AlarmManager() {}

    public static void triggerAlarm(Runnable runnable) {
        ALARM_EXECUTOR.execute(runnable);
    }

    public static void doAlarm(DynamicExecutor executor) {
        List<NotifyItem> notifyItems = executor.getNotifyItems();
        notifyItems.forEach(notifyItem -> doAlarm(executor,notifyItem));
    }

    public static void doAlarm(DynamicExecutor executor, NotifyItem notifyItem) {

        boolean triggerCondition = false;

        NotifyTypeEnum notifyTypeEnum = notifyItem.getType();

        if (notifyTypeEnum == NotifyTypeEnum.REJECT) {
            return;
        } else if (notifyTypeEnum == NotifyTypeEnum.CAPACITY) {
            triggerCondition = checkCapacity(executor);
        } else if (notifyTypeEnum == NotifyTypeEnum.ACTIVES) {
            triggerCondition = checkActives(executor);
        }
        if (!triggerCondition) {
            return;
        }

//        boolean ifAlarm = AlarmLimiter.ifAlarm(executor, notifyTypeEnum.getValue());
//        if (!ifAlarm) {
//            log.warn("DynamicExecutor notify, alarm limit, Name: {}, type: {}",
//                    executor.getThreadPoolName(), notifyTypeEnum.getValue());
//            return;
//        }

    }

    private static boolean checkActives(DynamicExecutor executor) {

        NotifyItem notifyItem = NotifyHelper.getNotifyItem(executor, NotifyTypeEnum.ACTIVES);
        if (Objects.isNull(notifyItem)) {
            return false;
        }

        int maximumPoolSize = executor.getMaximumPoolSize();
        double div = NumberUtil.div(executor.getActiveCount(), maximumPoolSize, 2) * 100;
        return notifyItem.isEnabled() && div >= notifyItem.getThreshold();
    }

    private static boolean checkCapacity(DynamicExecutor executor) {
        BlockingQueue<Runnable> workQueue = executor.getQueue();
        if (CollUtil.isEmpty(workQueue)) {
            return false;
        }

        NotifyItem notifyItem = NotifyHelper.getNotifyItem(executor, NotifyTypeEnum.CAPACITY);
        if (Objects.isNull(notifyItem)) {
            return false;
        }

        int queueCapacity = executor.getQueueCapacity();
        double div = NumberUtil.div(workQueue.size(), queueCapacity, 2) * 100;
        return notifyItem.isEnabled() && div >= notifyItem.getThreshold();
    }




}
